#include<mips/regdef.h>
#include<sys/syscall.h>


########## STACK FRAME ##########
#define REC_SFSIZE 40
########## CALLER ARGS ##########
#define REC_FRAME_A1 44
#define REC_FRAME_A0 40
##########     SRA     ##########
#define REC_FRAME_RA 32
#define REC_FRAME_FP 28
#define REC_FRAME_GP 24
##########     LTA     ##########
#define REC_FRAME_TEMP1 16

##########     ABA     ##########
#define REC_FRAME_ARG3 12
#define REC_FRAME_ARG2 8
#define REC_FRAME_ARG1 4
#define REC_FRAME_ARG0 0
	.align	2
	.local	recursive
	.ent	recursive


recursive:    # void recursive (int fd,int num)

	.frame	$fp, REC_SFSIZE, ra 	#indicacion del frame area

	subu	sp, sp, REC_SFSIZE  	#reservo el espacio de stack
	.cprestore	REC_FRAME_GP		#indico donde guardar el gp
	sw	$fp, REC_FRAME_FP(sp)		#guardo el fp en SRA
	sw	ra, REC_FRAME_RA(sp)		#guardo la posicion de retorno en SRA
	move	$fp, sp

	# Argumentos de funcion
	sw	a0, REC_FRAME_A0($fp)		# a0: int fd
	sw	a1, REC_FRAME_A1($fp)		# a1: unsigned int numero

	lw t0,REC_FRAME_A1($fp)
	remu t1,t0,10 					#resto m:n%10: 204:(rsto m, n)(4,20) (0,2) (2,0)
	sw t1,REC_FRAME_TEMP1($fp)
	div t0,t0,10 					# n = n/10
	beqz t0,print

notequalz:
	lw a0, REC_FRAME_A0($fp)
	sw t0, REC_FRAME_A1($fp)
	lw a1, REC_FRAME_A1($fp)
	la t9, recursive
	jal t9

print:
	#code
	li	v0, SYS_write 				#<sys/syscall.h>.
	#li	a0, 1    # a0: stdout  		#descomentar esta linea para stdout
	lw a0,REC_FRAME_A0($fp) 		#obtiene el fd

	li	a2, 1    					#a2: length 2 pq son de 48 a 58
	#cargar el numero en t3
	lw t3, REC_FRAME_TEMP1($fp)
	addiu t3,t3,48  #t3+=48
	sw t3,REC_FRAME_TEMP1($fp)
	addu a1,$fp,REC_FRAME_TEMP1 	#paso el puntero
	syscall


	beqz	a3, return_recursive		# si a3 es igual a cero return ok


error_write_recu:
	li	a0, 1			# exit 1 error.
	li v0, SYS_exit
	syscall

return_recursive:
	lw ra, REC_FRAME_RA($fp)
	lw	$fp, REC_FRAME_FP(sp)		# recupero fp
	addu	sp, sp, REC_SFSIZE		# destruyo el stack frame
	jr	ra
	
	.end	recursive
	.size	recursive, .-recursive




	.text
	.align	2
	.local	write
	.ent	write

########## STACK FRAME ##########
#define WR_SFSIZE 32

########## CALLER ARGS ##########
#define WR_FRAME_A1 36
#define WR_FRAME_A0 32

##########     SRA     ##########
#4 bytes de padding
#define WR_FRAME_RA 24
#define WR_FRAME_FP 20
#define WR_FRAME_GP 16

##########     LTA     ##########
#no hay variables locales
##########     ABA     ##########
#define WR_FRAME_ARG3 12
#define WR_FRAME_ARG2 8
#define WR_FRAME_ARG1 4
#define WR_FRAME_ARG0 0

write:    # void write (int fd, unsigned int numero)

	.frame	$fp, WR_SFSIZE, ra 		#indicacion del frame area

	subu	sp, sp, WR_SFSIZE  		#reservo el espacio de stack
	.cprestore	WR_FRAME_GP			#indico donde guardar el gp
	sw	$fp, WR_FRAME_FP(sp)		#guardo el fp en SRA
	sw	ra, WR_FRAME_RA(sp)			#guardo la posicion de retorno en SRA
	move	$fp, sp


	# Argumentos de funcion
	sw	a0, WR_FRAME_A0($fp)		# a0: int fd
	sw	a1, WR_FRAME_A1($fp)		# a1: unsigned int numero

	#code
	#a0:fd
	#a1:num
	lw a0,WR_FRAME_A0($fp)
	lw a1,WR_FRAME_A1($fp)
	jal recursive

	
	lw ra, WR_FRAME_RA($fp)
	lw	$fp, WR_FRAME_FP(sp)		# recupero fp
	addu	sp, sp, WR_SFSIZE		# destruyo el stack frame

	jr ra

	.end	write
	.size	write, .-write




#####		WRITE_ENC		#####


write_enc:    # void write_enc (int fd, char * string, int bytes)
	.text
	.align	2
	.local	write_enc
	.ent	write_enc


########## STACK FRAME ##########
#define WRE_SFSIZE 32

########## CALLER ARGS ##########
#define WRE_FRAME_A2 40
#define WRE_FRAME_A1 36
#define WRE_FRAME_A0 32

##########     SRA     ##########
#4 byte padding
#define WRE_FRAME_RA 24
#define WRE_FRAME_FP 20
#define WRE_FRAME_GP 16

##########     LTA     ##########
#sin variables
##########     ABA     ##########
#define WRE_FRAME_ARG3 12
#define WRE_FRAME_ARG2 8
#define WRE_FRAME_ARG1 4
#define WRE_FRAME_ARG0 0

#########  CONSTANTES  #########


	.frame	$fp, WRE_SFSIZE, ra 	#indicacion del frame area

	subu	sp, sp, WRE_SFSIZE  	#reservo el espacio de stack
	.cprestore	WRE_FRAME_GP		#indico donde guardar el gp
	sw	$fp, WRE_FRAME_FP(sp)		#guardo el fp en SRA
	sw	ra, WRE_FRAME_RA(sp)		#guardo la posicion de retorno en SRA
	move	$fp, sp

	# Argumentos de funcion#
	sw	a0, WRE_FRAME_A0($fp)		# a0: int fd
	sw	a1, WRE_FRAME_A1($fp)		# a1: posicion inicial
	sw	a2, WRE_FRAME_A2($fp)		# a2: cantidad de bytes

#Comienzo de la funcion

	lw	a0, WRE_FRAME_A0($fp)			# en a0 tengo outfd
	lw	a1, WRE_FRAME_A1($fp)			# en a1 tengo la direccion inicial del string
	lw	a2, WRE_FRAME_A2($fp)			# cargo en a2 la long, para escribir
	li	v0, SYS_write					# llamo a write
	syscall

	beqz	a3, return_write_enc		# si a3 es igual a cero return ok


error_write:
	li	a0, 1							# exit 1 error.
	li v0, SYS_exit
	syscall

return_write_enc:
#rutina de retorno
	lw	ra, WRE_FRAME_RA(sp)
	lw	$fp, WRE_FRAME_FP(sp)			# recupero fp
	addu	sp, sp, WRE_SFSIZE			# destruyo el stack frame
	jr	ra
	
	.end	write_enc
	.size	write_enc, .-write_enc

#####		MIPS32_PLOT		#####

mips32_plot:								# void mips32_plot(param_t *parms);

	.text
	.align	2
	.globl	mips32_plot
	.ent	mips32_plot
########## STACK FRAME ##########
#define PLOT_SFSIZE 76

########## CALLER ARGS ##########
#define PLOT_FRAME_A0 76

##########     SRA     ##########
# se agrega un word de padding 
#ya que cualquier area tiene que estar alineada a 8 bytes
#define PLOT_FRAME_RA 72
#define PLOT_FRAME_FP 68
#define PLOT_FRAME_GP 64

##########     LTA     ##########
#define PLOT_FRAME_CCERO_RE 60
#define PLOT_FRAME_CCERO_IM 56
#define PLOT_FRAME_INICIAL_RE 52
#define PLOT_FRAME_INICIAL_IM 48
#define PLOT_FRAME_CONT_X 44
#define PLOT_FRAME_CONT_Y 40
#define PLOT_FRAME_NUM_VUELTAS 36
#define PLOT_FRAME_ACTUAL_IM 32
#define PLOT_FRAME_ACTUAL_RE 28
#define PLOT_FRAME_PASO_IM 24
#define PLOT_FRAME_PASO_RE 20
#define PLOT_FRAME_FD 16

##########     ABA     ##########
#define PLOT_FRAME_ARG3 12
#define PLOT_FRAME_ARG2 8
#define PLOT_FRAME_ARG1 4
#define PLOT_FRAME_ARG0 0
##########     PARAMS STRUCT     ##########
#define PLOT_PARAM_UL_RE 0
#define PLOT_PARAM_UL_IM 4
#define PLOT_PARAM_LR_RE 8
#define PLOT_PARAM_LR_IM 12
#define PLOT_PARAM_D_RE 16
#define PLOT_PARAM_D_IM 20
#define PLOT_PARAM_X_RES 24
#define PLOT_PARAM_Y_RES 28
#define PLOT_PARAM_SHADES 32
#define PLOT_PARAM_FILE 36
# El FILE * segun offsetof en netbsd da 14 bytes.
#tomo el word anterior para que no de lectura desalineada.
#define PLOT_PARAM_FP_FD 12 
#define PLOT_PARAM_CORR 16


	.frame	$fp, PLOT_SFSIZE, ra 	#indicacion del frame area, CHEQUEAR ESTO

	subu	sp, sp, PLOT_SFSIZE  	#reservo el espacio de stack
	.cprestore	PLOT_FRAME_GP		#indico donde guardar el gp
	sw	$fp, PLOT_FRAME_FP(sp)		#guardo el fp en SRA
	sw	ra, PLOT_FRAME_RA(sp)		#guardo la posicion de retorno en SRA
	move	$fp, sp

	sw	a0, PLOT_FRAME_A0($fp) 			#almaceno el parametro en el aba superior.



	#obtencion del fd el FILE
	lw	t0, PLOT_PARAM_FILE(a0)			# cargo la posicion del fd
	lw	t0, PLOT_PARAM_FP_FD(t0) 		# cargo un word con el fd en la parte superior
	srl t0,t0,PLOT_PARAM_CORR			# corro a la parte baja
	sw t0,PLOT_FRAME_FD($fp)			# guardo en una variable

	
	###### ESCRITURA DEL ENCABEZADO DEL ARCHIVO #########
	#tipo de archivo
	lw a0,PLOT_FRAME_FD($fp) 			#El FD
	la a1,enc 							#pos inicial del vector de caracteres
	li a2,3         					#long del vector encabezado a imprimir
	la	t9, write_enc
	jal t9
	

	#res x
	lw a0,PLOT_FRAME_FD($fp) 		#El FD
	lw t0,PLOT_FRAME_A0($fp)		#cargo el puntero a los params
	lw a1,PLOT_PARAM_X_RES(t0) 		#x_res
	la	t9, write
	jal t9

	#salto de linea
	lw a0,PLOT_FRAME_FD($fp) 		#El FD
	la a1,salto
	li a2,1         				#1 byte
	la	t9, write_enc
	jal t9
	
	#res y
	lw a0,PLOT_FRAME_FD($fp) 		#El FD
	lw t0,PLOT_FRAME_A0($fp)		#cargo el puntero a los params
	lw a1,PLOT_PARAM_Y_RES(t0) 		#y_res
	la	t9, write
	jal t9
	
	#salto de linea
	lw a0,PLOT_FRAME_FD($fp) 		#El FD
	la a1,salto
	li a2,1         				#1 byte
	la	t9, write_enc
	jal t9
	

	lw a0,PLOT_FRAME_FD($fp) 		#El FD
	lw t0,PLOT_FRAME_A0($fp)		#cargo el puntero a los params
	lw a1,PLOT_PARAM_SHADES(t0) 		#shades
	la	t9, write
	jal t9

	#salto de linea
	lw a0,PLOT_FRAME_FD($fp) 		#El FD
	la a1,salto
	li a2,1         				#1 byte
	la	t9, write_enc
	jal t9
	
	###### FIN DE ENCABEZADO DE PGM #########
	
	#ejemplos
	#escribo espacio
	#lw a0,PLOT_FRAME_FD($fp) 		#El FD
	#la a1,espacio
	#li a2,1         				#bytes
	#la	t9, write_enc
	#jal t9
	
	#escribo 189
	#lw a0,PLOT_FRAME_FD($fp)
	#li a1,189
	#jal write


	#lw ra, PLOT_FRAME_RA(sp)
	#addu sp,sp,PLOT_SFSIZE
	#j ra
	#Para acceder a cualquier atributo de la estructura se puede hacer
	# lw	t0, PLOT_FRAME_A0($fp) carga el puntero de la estructura
	# lw	t0, PLOT_PARAM_ATTR_NAME(t0) donde ATTR_NAME es el nombre del attributo

########  INICIO DEL CALCULO   ########
calculo_valores_iniciales:
	##Calculo el paso en X##
	#Pruebo con el paso RE que viene en los param.
	lw 	t0, PLOT_FRAME_A0($fp)
	lwc1	$f12, PLOT_PARAM_D_RE(t0)
	swc1	$f12, PLOT_FRAME_PASO_RE($fp)	#Guardo en la variable el valor de t1
	
	##Calculo el paso en Y##
	#Pruebo con el paso IM que viene en los params.
	lw 	t0, PLOT_FRAME_A0($fp)
	lwc1	$f12, PLOT_PARAM_D_IM(t0)
	swc1	$f12, PLOT_FRAME_PASO_IM($fp)	#Guardo en la variable el valor de t1


	##Calculos el punto inicial RE##
	lwc1	$f2, PLOT_FRAME_PASO_RE($fp)	#Cargo el PASO_RE
	li		t3, 2
	mtc1	t3, $f4
	cvt.s.w $f4, $f4 
	div.s	$f2, $f2, $f4					#Calculo medio paso RE
	lw	t0, PLOT_FRAME_A0($fp)
	lwc1	$f0, PLOT_PARAM_UL_RE(t0)		#Cargo el UL_RE en t0
	add.s	$f0, $f0, $f2					#Le sumo medio paso al punto inicial en RE
	swc1	$f0, PLOT_FRAME_INICIAL_RE($fp)

	##Calculo el punto inicial IM##
	lwc1	$f2, PLOT_FRAME_PASO_IM($fp)
	div.s	$f2, $f2, $f4					#Calculo medio paso IM
	lw	t0, PLOT_FRAME_A0($fp)
	lwc1	$f0, PLOT_PARAM_UL_IM(t0)		#Cargo el UL_IM en t0
	sub.s	$f0, $f0, $f2					#Le sumo medio paso al punto inicial en IM
	swc1	$f0, PLOT_FRAME_INICIAL_IM($fp)

	##Inicio los contadores en 0##
	li	t3, 0
	sw	t3, PLOT_FRAME_CONT_X($fp)	#Inicio el contador X en 0
	sw	t3, PLOT_FRAME_CONT_Y($fp)	#inciio el contador Y en 0


loop_res:
	##Cargo los registros a usar en el loop##
	lw	t2, PLOT_FRAME_CONT_X($fp)
	lw	t3, PLOT_FRAME_CONT_Y($fp)
	lwc1	$f4, PLOT_FRAME_PASO_RE($fp)
	lwc1	$f10, PLOT_FRAME_PASO_IM($fp)
	lwc1	$f6, PLOT_FRAME_INICIAL_RE($fp)
	lwc1	$f12, PLOT_FRAME_INICIAL_IM($fp)

	##Calculo offset actual RE##
	mtc1	t2, $f8
	cvt.s.w	$f8, $f8
	mul.s	$f0, $f8, $f4			#Calculo el offset en X numPasoX * PasoX

	##Calculo el offset actual IM##
	mtc1	t3, $f8
	cvt.s.w	$f8, $f8
	mul.s	$f2, $f8, $f10			#Calculo el offset en Y numPasoY * PasoY

	##Sumo el offset al punto incial##
	add.s	$f0, $f6, $f0			#InicialX + offsetX
	sub.s	$f2, $f12, $f2			#InicialY - offsetY
	swc1	$f0, PLOT_FRAME_ACTUAL_RE($fp)	#Guardo el valor con el que trabajo actualmente
	swc1	$f2, PLOT_FRAME_ACTUAL_IM($fp)	
	swc1	$f0, PLOT_FRAME_CCERO_RE($fp)	#Guardo el primer de la serie para el calculo de los posteriores.
	swc1	$f2, PLOT_FRAME_CCERO_IM($fp)

	##Inicio el numero de vueltas del color en 0##
	li	t3, 0
	sw	t3, PLOT_FRAME_NUM_VUELTAS($fp)	#Inicio el numero de vueltas en 0

loop_calculo:
	##Cargo los registros para el calculo##
	lwc1	$f0, PLOT_FRAME_ACTUAL_RE($fp)
	lwc1	$f4, PLOT_FRAME_ACTUAL_IM($fp)

	##Calculo el valor absoluto del punto##
	mul.s	$f0, $f0, $f0			#t0^2
	mul.s	$f4, $f4, $f4			#t1^2
	add.s	$f2, $f0, $f4			#t2 = t1 + t0
	cvt.w.s $f2, $f2
	mfc1	t2, $f2				#casteo a int
	li	t3, 4
	bgt	t2, t3, salir_calculo		#if abs(z) > 4 Salto fuera del loop de calculo

	##Sumo uno a las vueltas##
	lw	t3, PLOT_FRAME_NUM_VUELTAS($fp)
	li  	t4, 1
	add	t3, t3, t4			#NUM_VUELTAS++
	sw	t3, PLOT_FRAME_NUM_VUELTAS($fp)

	##Calculo el siguiente punto de la serie RE##
	lwc1	$f0, PLOT_FRAME_ACTUAL_RE($fp)
	lwc1	$f6, PLOT_FRAME_ACTUAL_IM($fp)
	lwc1	$f12, PLOT_FRAME_CCERO_RE($fp)
	lwc1	$f14, PLOT_FRAME_CCERO_IM($fp)
	mul.s	$f2, $f0, $f0			#t2 = RE^2
	mul.s	$f2, $f2, $f0			#t2 = RE^3
	mul.s	$f8, $f6, $f6			#t3 = IM^2
	mul.s	$f8, $f8, $f0			#t3 = IM^2 * RE
	li		t0, 3
	mtc1	t0, $f4
	cvt.s.w $f4, $f4
	mul.s	$f8, $f8, $f4
	sub.s	$f2, $f2, $f8			# RE(Z^3) = a^3 - 3ab^2
	add.s 	$f2, $f2, $f12
	swc1	$f2, PLOT_FRAME_ACTUAL_RE($fp)

	##Calculo el siguiente punto de la seria IM##
	mul.s	$f8, $f6, $f6
	mul.s	$f8, $f8, $f6
	mul.s	$f2, $f0, $f0
	mul.s	$f2, $f2, $f6
	mul.s	$f2, $f2, $f4
	sub.s	$f2, $f2, $f8
	add.s 	$f2, $f2, $f14
	swc1	$f2, PLOT_FRAME_ACTUAL_IM($fp)	# IM(Z^3) = 3ba^2 - b^3

	##Me fijo si alcance el numero maximo de vueltas##
	li	t0, 255
	lw	t1, PLOT_FRAME_NUM_VUELTAS($fp)
	bgt	t0, t1, loop_calculo		#if 256 > num_vueltas otro loop

salir_calculo:
	#escribo el numero de vueltas
	lw a0,PLOT_FRAME_FD($fp)
	lw a1, PLOT_FRAME_NUM_VUELTAS($fp)
	la t9,write
	jal t9

	#escribo un espacio
	lw a0,PLOT_FRAME_FD($fp) 		#El FD
	la a1,espacio
	li a2,1         					#bytes
	la	t9, write_enc
	jal t9
	
	##Me muevo un paso en X##
	lw  t0, PLOT_FRAME_CONT_X($fp)
	li  t1, 1
	add t0, t0, t1
	sw  t0, PLOT_FRAME_CONT_X($fp)	#ContX++

	##Me fijo si llegue al final de la linea, sino salto al loop_res##
	lw	t1, PLOT_FRAME_A0($fp)
	lw	t1, PLOT_PARAM_X_RES(t1)	#t1 = resX
	blt t0, t1, loop_res 			#if t0 < t1 loop_res

	##escribo un enter para empezar una nueva linea##
 	lw a0,PLOT_FRAME_FD($fp) 		#El FD
	la a1,salto
	li a2,1         					#bytes
	la	t9, write_enc
	jal t9

	##Si no salte pongo en contador de X en 0##
	li  t0, 0
	sw  t0, PLOT_FRAME_CONT_X($fp)  #ContX = 0

	##Avanzo el contador de Y en 1##
	li  t1, 1
	lw  t0, PLOT_FRAME_CONT_Y($fp)
	add t0, t0, t1
	sw  t0, PLOT_FRAME_CONT_Y($fp)	#ContY++

	##Me fijo si llegue a la ultima linea, sino salto al loop_res para seguir##
	lw  t1, PLOT_FRAME_A0($fp)
	lw  t1, PLOT_PARAM_Y_RES(t1) 	#t1 = resY 
	blt t0, t1, loop_res
	
	######## FIN DE LA FUNCION ########
	lw	ra, PLOT_FRAME_RA(sp)
	lw	$fp, PLOT_FRAME_FP(sp)		# recupero fp
	addu	sp, sp, PLOT_SFSIZE		# destruyo el stack frame
	jr	ra

	.end	mips32_plot
	.size	mips32_plot, .-mips32_plot

	.rdata		# data segment
	.align	1

#########		b16_errmg		#########

enc: .asciiz "P2\n"
salto: .asciiz "\n"
espacio: .asciiz " "	



